#include <windows.h>

#include "lib.h"
#include "ccr.h"

// this implementation assumes FIFO semaphores (otherwise it fails)
//

ConditionalCriticalRegion::ConditionalCriticalRegion()
{
	mutex = delay = (HANDLE)0;
	count = temp = 0;

	mutex = CreateSemaphore(NULL, 1, 1, NULL);
	delay = CreateSemaphore(NULL, 0, 1, NULL);
}

ConditionalCriticalRegion::~ConditionalCriticalRegion()
{
	if (mutex)
	{
		CloseHandle(mutex);
		mutex = (HANDLE)0;
	}

	if (delay)
	{
		CloseHandle(delay);
		delay = (HANDLE)0;
	}
}

bool8
ConditionalCriticalRegion::initOk()
{
	return (bool8)(mutex && delay);
}

void
ConditionalCriticalRegion::begin()
{
	WaitForSingleObject(mutex, INFINITE);
}

void
ConditionalCriticalRegion::end()
{
	if (count > 0)
	{
		temp = 0;
		ReleaseSemaphore(delay, 1, NULL);
	}
	else
		ReleaseSemaphore(mutex, 1, NULL);
}

void
ConditionalCriticalRegion::await(Condition condition, void* User)
{
	if (!condition(User))
	{
		++count;
		ReleaseSemaphore(mutex, 1, NULL);
		WaitForSingleObject(delay, INFINITE);

		while (!condition(User))
		{
			++temp;
			if (temp < count)
				ReleaseSemaphore(delay, 1, NULL);
			else
				ReleaseSemaphore(mutex, 1, NULL);

			WaitForSingleObject(delay, INFINITE);
		}
		--count;
	}
}
